<?php

/**
 * JPGraph v4.0.3
 */

namespace lemon\JpGraph\Image;

use lemon\JpGraph\Util;

/*
 * File:		JPGRAPH_LED.PHP
 * // Description: Module to generate Dotted LED-like digits
 * // Created:	 2006-11-26
 * // Ver:		 $Id: jpgraph_led.php 1674 2009-07-22 19:42:23Z ljp $
 * //
 * // Copyright 2006 (c) Asial Corporation. All rights reserved.
 * //
 * // Changed: 2007-08-06 by Alexander Kurochkin (inspector@list.ru)
 */
// Constants for color schema
define('LEDC_RED', 0);
define('LEDC_GREEN', 1);
define('LEDC_BLUE', 2);
define('LEDC_YELLOW', 3);
define('LEDC_GRAY', 4);
define('LEDC_CHOCOLATE', 5);
define('LEDC_PERU', 6);
define('LEDC_GOLDENROD', 7);
define('LEDC_KHAKI', 8);
define('LEDC_OLIVE', 9);
define('LEDC_LIMEGREEN', 10);
define('LEDC_FORESTGREEN', 11);
define('LEDC_TEAL', 12);
define('LEDC_STEELBLUE', 13);
define('LEDC_NAVY', 14);
define('LEDC_INVERTGRAY', 15);

// Check that mb_strlen() is available
if (!function_exists('mb_strlen')) {
	Util\JpGraphError::RaiseL(25500);
	//'Multibyte strings must be enabled in the PHP installation in order to run the LED module
	// so that the function mb_strlen() is available. See PHP documentation for more information.'
}

/**
 * @class DigitalLED74
 * // Description:
 * // Construct a number as an image that looks like LED numbers in a
 * // 7x4 digital matrix
 */
class DigitalLED74
{
	private $iLED_X	   = 4;
	private $iLED_Y	   = 7;
	private $iColorSchema = [
		LEDC_RED		 => ['red', 'darkred:0.9', 'red:0.3'], // 0
		LEDC_GREEN	   => ['green', 'darkgreen', 'green:0.3'], // 1
		LEDC_BLUE		=> ['lightblue:0.9', 'darkblue:0.85', 'darkblue:0.7'], // 2
		LEDC_YELLOW	  => ['yellow', 'yellow:0.4', 'yellow:0.3'], // 3
		LEDC_GRAY		=> ['gray:1.4', 'darkgray:0.85', 'darkgray:0.7'],
		LEDC_CHOCOLATE   => ['chocolate', 'chocolate:0.7', 'chocolate:0.5'],
		LEDC_PERU		=> ['peru:0.95', 'peru:0.6', 'peru:0.5'],
		LEDC_GOLDENROD   => ['goldenrod', 'goldenrod:0.6', 'goldenrod:0.5'],
		LEDC_KHAKI	   => ['khaki:0.7', 'khaki:0.4', 'khaki:0.3'],
		LEDC_OLIVE	   => ['#808000', '#808000:0.7', '#808000:0.6'],
		LEDC_LIMEGREEN   => ['limegreen:0.9', 'limegreen:0.5', 'limegreen:0.4'],
		LEDC_FORESTGREEN => ['forestgreen', 'forestgreen:0.7', 'forestgreen:0.5'],
		LEDC_TEAL		=> ['teal', 'teal:0.7', 'teal:0.5'],
		LEDC_STEELBLUE   => ['steelblue', 'steelblue:0.65', 'steelblue:0.5'],
		LEDC_NAVY		=> ['navy:1.3', 'navy:0.95', 'navy:0.8'], //14
		LEDC_INVERTGRAY  => ['darkgray', 'lightgray:1.5', 'white'], //15
	];
	private $iLEDSpec = [
		0	=> [6, 9, 11, 15, 13, 9, 6],
		1	=> [2, 6, 10, 2, 2, 2, 2],
		2	=> [6, 9, 1, 2, 4, 8, 15],
		3	=> [6, 9, 1, 6, 1, 9, 6],
		4	=> [1, 3, 5, 9, 15, 1, 1],
		5	=> [15, 8, 8, 14, 1, 9, 6],
		6	=> [6, 8, 8, 14, 9, 9, 6],
		7	=> [15, 1, 1, 2, 4, 4, 4],
		8	=> [6, 9, 9, 6, 9, 9, 6],
		9	=> [6, 9, 9, 7, 1, 1, 6],
		'!'  => [4, 4, 4, 4, 4, 0, 4],
		'?'  => [6, 9, 1, 2, 2, 0, 2],
		'#'  => [0, 9, 15, 9, 15, 9, 0],
		'@'  => [6, 9, 11, 11, 10, 9, 6],
		'-'  => [0, 0, 0, 15, 0, 0, 0],
		'_'  => [0, 0, 0, 0, 0, 0, 15],
		'='  => [0, 0, 15, 0, 15, 0, 0],
		'+'  => [0, 0, 4, 14, 4, 0, 0],
		'|'  => [4, 4, 4, 4, 4, 4, 4], //vertical line, used for simulate rus 'Ы'
		','  => [0, 0, 0, 0, 0, 12, 4],
		'.'  => [0, 0, 0, 0, 0, 12, 12],
		':'  => [12, 12, 0, 0, 0, 12, 12],
		';'  => [12, 12, 0, 0, 0, 12, 4],
		'['  => [3, 2, 2, 2, 2, 2, 3],
		']'  => [12, 4, 4, 4, 4, 4, 12],
		'('  => [1, 2, 2, 2, 2, 2, 1],
		')'  => [8, 4, 4, 4, 4, 4, 8],
		'{'  => [3, 2, 2, 6, 2, 2, 3],
		'}'  => [12, 4, 4, 6, 4, 4, 12],
		'<'  => [1, 2, 4, 8, 4, 2, 1],
		'>'  => [8, 4, 2, 1, 2, 4, 8],
		'*'  => [9, 6, 15, 6, 9, 0, 0],
		'"'  => [10, 10, 0, 0, 0, 0, 0],
		'\'' => [4, 4, 0, 0, 0, 0, 0],
		'`'  => [4, 2, 0, 0, 0, 0, 0],
		'~'  => [13, 11, 0, 0, 0, 0, 0],
		'^'  => [4, 10, 0, 0, 0, 0, 0],
		'\\' => [8, 8, 4, 6, 2, 1, 1],
		'/'  => [1, 1, 2, 6, 4, 8, 8],
		'%'  => [1, 9, 2, 6, 4, 9, 8],
		'&'  => [0, 4, 10, 4, 11, 10, 5],
		'$'  => [2, 7, 8, 6, 1, 14, 4],
		' '  => [0, 0, 0, 0, 0, 0, 0],
		'•'  => [0, 0, 6, 6, 0, 0, 0], //149
		'°'  => [14, 10, 14, 0, 0, 0, 0], //176
		'†'  => [4, 4, 14, 4, 4, 4, 4], //134
		'‡'  => [4, 4, 14, 4, 14, 4, 4], //135
		'±'  => [0, 4, 14, 4, 0, 14, 0], //177
		'‰'  => [0, 4, 2, 15, 2, 4, 0], //137 show right arrow
		'™'  => [0, 2, 4, 15, 4, 2, 0], //156 show left arrow
		'Ў'  => [0, 0, 8, 8, 0, 0, 0], //159 show small hi-stick - that need for simulate rus 'Ф'
		"\t" => [8, 8, 8, 0, 0, 0, 0], //show hi-stick - that need for simulate rus 'У'
		"\r" => [8, 8, 8, 8, 8, 8, 8], //vertical line - that need for simulate 'M', 'W' and rus 'М','Ш' ,'Щ'
		"\n" => [15, 15, 15, 15, 15, 15, 15], //fill up - that need for simulate rus 'Ж'
		'Ґ'  => [10, 5, 10, 5, 10, 5, 10], //chess
		'µ'  => [15, 0, 15, 0, 15, 0, 15], //4 horizontal lines
		// latin
		'A'  => [6, 9, 9, 15, 9, 9, 9],
		'B'  => [14, 9, 9, 14, 9, 9, 14],
		'C'  => [6, 9, 8, 8, 8, 9, 6],
		'D'  => [14, 9, 9, 9, 9, 9, 14],
		'E'  => [15, 8, 8, 14, 8, 8, 15],
		'F'  => [15, 8, 8, 14, 8, 8, 8],
		'G'  => [6, 9, 8, 8, 11, 9, 6],
		'H'  => [9, 9, 9, 15, 9, 9, 9],
		'I'  => [14, 4, 4, 4, 4, 4, 14],
		'J'  => [15, 1, 1, 1, 1, 9, 6],
		'K'  => [8, 9, 10, 12, 12, 10, 9],
		'L'  => [8, 8, 8, 8, 8, 8, 15],
		'M'  => [8, 13, 10, 8, 8, 8, 8], // need to add \r
		'N'  => [9, 9, 13, 11, 9, 9, 9],
		'O'  => [6, 9, 9, 9, 9, 9, 6],
		'P'  => [14, 9, 9, 14, 8, 8, 8],
		'Q'  => [6, 9, 9, 9, 13, 11, 6],
		'R'  => [14, 9, 9, 14, 12, 10, 9],
		'S'  => [6, 9, 8, 6, 1, 9, 6],
		'T'  => [14, 4, 4, 4, 4, 4, 4],
		'U'  => [9, 9, 9, 9, 9, 9, 6],
		'V'  => [0, 0, 0, 10, 10, 10, 4],
		'W'  => [8, 8, 8, 8, 10, 13, 8], // need to add \r
		'X'  => [9, 9, 6, 6, 6, 9, 9],
		'Y'  => [10, 10, 10, 10, 4, 4, 4],
		'Z'  => [15, 1, 2, 6, 4, 8, 15],
		// russian utf-8
		'А'  => [6, 9, 9, 15, 9, 9, 9],
		'Б'  => [14, 8, 8, 14, 9, 9, 14],
		'В'  => [14, 9, 9, 14, 9, 9, 14],
		'Г'  => [15, 8, 8, 8, 8, 8, 8],
		'Д'  => [14, 9, 9, 9, 9, 9, 14],
		'Е'  => [15, 8, 8, 14, 8, 8, 15],
		'Ё'  => [6, 15, 8, 14, 8, 8, 15],
		//Ж is combine: >\n<
		'З'  => [6, 9, 1, 2, 1, 9, 6],
		'И'  => [9, 9, 9, 11, 13, 9, 9],
		'Й'  => [13, 9, 9, 11, 13, 9, 9],
		'К'  => [9, 10, 12, 10, 9, 9, 9],
		'Л'  => [7, 9, 9, 9, 9, 9, 9],
		'М'  => [8, 13, 10, 8, 8, 8, 8], // need to add \r
		'Н'  => [9, 9, 9, 15, 9, 9, 9],
		'О'  => [6, 9, 9, 9, 9, 9, 6],
		'П'  => [15, 9, 9, 9, 9, 9, 9],
		'Р'  => [14, 9, 9, 14, 8, 8, 8],
		'С'  => [6, 9, 8, 8, 8, 9, 6],
		'Т'  => [14, 4, 4, 4, 4, 4, 4],
		'У'  => [9, 9, 9, 7, 1, 9, 6],
		'Ф'  => [2, 7, 10, 10, 7, 2, 2], // need to add Ў
		'Х'  => [9, 9, 6, 6, 6, 9, 9],
		'Ц'  => [10, 10, 10, 10, 10, 15, 1],
		'Ч'  => [9, 9, 9, 7, 1, 1, 1],
		'Ш'  => [10, 10, 10, 10, 10, 10, 15], // \r
		'Щ'  => [10, 10, 10, 10, 10, 15, 0], // need to add \r
		'Ъ'  => [12, 4, 4, 6, 5, 5, 6],
		'Ы'  => [8, 8, 8, 14, 9, 9, 14], // need to add |
		'Ь'  => [8, 8, 8, 14, 9, 9, 14],
		'Э'  => [6, 9, 1, 7, 1, 9, 6],
		'Ю'  => [2, 2, 2, 3, 2, 2, 2], // need to add O
		'Я'  => [7, 9, 9, 7, 3, 5, 9],
	];
	private $iSuperSampling = 3;
	private $iMarg		  = 1;
	private $iRad		   = 4;

	public function __construct($aRadius = 2, $aMargin = 0.6){
		$this->iRad  = $aRadius;
		$this->iMarg = $aMargin;
	}

	public function SetSupersampling($aSuperSampling = 2){
		$this->iSuperSampling = $aSuperSampling;
	}

	public function _GetLED($aLedIdx, $aColor = 0){
		$width  = $this->iLED_X * $this->iRad * 2 + ($this->iLED_X + 1) * $this->iMarg + $this->iRad;
		$height = $this->iLED_Y * $this->iRad * 2 + ($this->iLED_Y) * $this->iMarg + $this->iRad * 2;

		// Adjust radious for supersampling
		$rad = $this->iRad * $this->iSuperSampling;

		// Margin in between "Led" dots
		$marg = $this->iMarg * $this->iSuperSampling;

		$swidth  = $width * $this->iSuperSampling;
		$sheight = $height * $this->iSuperSampling;

		$simg = new RotImage($swidth, $sheight, 0, DEFAULT_GFORMAT, false);
		$simg->SetColor($this->iColorSchema[$aColor][2]);
		$simg->FilledRectangle(0, 0, $swidth - 1, $sheight - 1);

		if (array_key_exists($aLedIdx, $this->iLEDSpec)) {
			$d = $this->iLEDSpec[$aLedIdx];
		} else {
			$d = [0, 0, 0, 0, 0, 0, 0];
		}

		for ($r = 0; $r < 7; ++$r) {
			$dr = $d[$r];
			for ($c = 0; $c < 4; ++$c) {
				if (($dr & pow(2, 3 - $c)) !== 0) {
					$color = $this->iColorSchema[$aColor][0];
				} else {
					$color = $this->iColorSchema[$aColor][1];
				}

				$x = 2 * $rad * $c + $rad + ($c + 1) * $marg + $rad;
				$y = 2 * $rad * $r + $rad + ($r + 1) * $marg + $rad;

				$simg->SetColor($color);
				$simg->FilledCircle($x, $y, $rad);
			}
		}

		$img = new Image($width, $height, DEFAULT_GFORMAT, false);
		$img->Copy($simg->img, 0, 0, 0, 0, $width, $height, $swidth, $sheight);
		$simg->Destroy();
		unset($simg);

		return $img;
	}

	public function Stroke($aValStr, $aColor = 0, $aFileName = ''){
		$this->StrokeNumber($aValStr, $aColor, $aFileName);
	}

	public function StrokeNumber($aValStr, $aColor = 0, $aFileName = ''){
		if ($aColor < 0 || $aColor >= safe_count($this->iColorSchema)) {
			$aColor = 0;
		}

		if (($n = mb_strlen($aValStr, 'utf8')) == 0) {
			$aValStr = ' ';
			$n	   = 1;
		}

		for ($i = 0; $i < $n; ++$i) {
			$d = mb_substr($aValStr, $i, 1, 'utf8');
			if (ctype_digit($d)) {
				$d = (int) $d;
			} else {
				$d = strtoupper($d);
			}
			$digit_img[$i] = $this->_GetLED($d, $aColor);
		}

		$w = imagesx($digit_img[0]->img);
		$h = imagesy($digit_img[0]->img);

		$number_img = new Image\Image($w * $n, $h, DEFAULT_GFORMAT, false);

		for ($i = 0; $i < $n; ++$i) {
			$number_img->Copy($digit_img[$i]->img, $i * $w, 0, 0, 0, $w, $h, $w, $h);
		}

		if ($aFileName != '') {
			$number_img->Stream($aFileName);
		} else {
			$number_img->Headers();
			$number_img->Stream();
		}
	}
}
